package Client;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;

import Messages.CreateFolderMsg;
import Messages.FileChangeMsg;
import Messages.Msg;
import Messages.MsgType;
import Messages.SendFileMsg;
import Messages.StartConnectionMsg;
import Messages.WhichActionMsg;
import Watcher.watchService;

/**
 * this is the class that implements the transferring the messages and file 
 * from the server (that receive it from the client) to the client
 * @author liel && guy
 *
 */
public class ServerToClient implements Runnable{
	
	ClientDetails clientDetails;
	Socket requestSocket;
	ObjectOutputStream out;
	ObjectInputStream in;
	Msg response;
	Msg request;
	String serverIp = "localhost";
	int socketPortToServer;
	int serverPort;
	boolean play;
	boolean stop;

	private static class Holder{
		volatile static ServerToClient serverToClientSingelton=new ServerToClient();
	}

	private ServerToClient() {
		super();
		socketPortToServer = 8899;
		serverPort = 8880;
		play = true;
	}
	/**
	 * receive the instance of the server to Client
	 * @return the instance of the server to Client
	 */
	public static ServerToClient getInstance(){
		return Holder.serverToClientSingelton;
	}
	/**
	 * set client details
	 * @param cd - the client details
	 */
	public void setClientDetails(ClientDetails cd){
		clientDetails = cd;

	}
	/**
	 * stop watch
	 */
	public void stopTransfer(){
		stop = true;
		synchronized (this) {
			notify();
		}
	}
	/**
	 * running the protocol
	 */
	public void run(){
		while (!stop) {
			while (play)
			{
				String strURL = "http://" + serverIp + ":" + serverPort
				+ "/waitServlet";
				try {
					//connect to the servlet that start the continuation and just suspend it
					URL continuationServlet = new URL(strURL);
					URLConnection connection = (URLConnection) continuationServlet
					.openConnection();
					connection.setAllowUserInteraction(true);
					connection.setDoOutput(true);
					out = new ObjectOutputStream(connection.getOutputStream());
					out.writeObject(clientDetails.getUserName());
					out.flush();

					in = new ObjectInputStream(connection.getInputStream());
					try {
						String test = (String) in.readObject();
					} catch (ClassNotFoundException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					in.close();
					out.close();
					//we are getting here if resumed was mad in the server
					if (!play)
						break;

					FileChangeMsg fileChangeMsg;

					requestSocket = new Socket(serverIp, socketPortToServer);
					System.out.println("Connected to " + serverIp + " in port "
							+ socketPortToServer);
					//2. get Input and Output streams
					out = new ObjectOutputStream(
							requestSocket.getOutputStream());
					out.flush();
					in = new ObjectInputStream(requestSocket.getInputStream());
					//3: Communicating with the server
					do {
						try {
							//Read the response
							response = (Msg) in.readObject();
							System.out.println("server>" + response.getType());
							//The new request
							switch (response.getType()) {
							case START:
								request = new StartConnectionMsg(clientDetails);
								sendMessage(request);
								break;
							case DELETE://delete the file
								System.out.println("in client start delete");
								fileChangeMsg = (FileChangeMsg) response;
								String fileName = fileChangeMsg.getFileName();
								File file = new File(
										clientDetails.getMainFolder() + "\\"
										+ fileChangeMsg.getFolder()
										+ "\\" + fileName);
								file.delete();
								request = getRequest();
								sendMessage(request);
								break;
							case SEND_FILE://create new file in the client
								System.out.println("in client send file");
								SendFileMsg sendFilemsg = (SendFileMsg) response;
								createFile(sendFilemsg.getFile(),
										sendFilemsg.getFolderName(),
										sendFilemsg.getFileName());
								request = getRequest();
								sendMessage(request);
								break;
							case CREATE_FOLDER://create new folder
								CreateFolderMsg createFolderMsg = (CreateFolderMsg) response;
								File f = new File(clientDetails.getMainFolder()
										+ "\\"
										+ createFolderMsg.getFolderName());
								try {
									if (f.mkdir()) {
										System.out
										.println("Directory Created - in path "
												+ f.getPath());
										watchService.getWsInstance()
										.addFolderToListen(f.getPath());
									} else
										System.out
										.println("Directory is not created");
								} catch (Exception e) {

								}
								request = getRequest();
								sendMessage(request);
								break;
							case BAD_DETAILS:
								System.out
								.println("userName or Password incorrent");
							case STOP:
								break;

							}
						} catch (ClassNotFoundException classNot) {
							System.err
							.println("data received in unknown format");
						}
					} while (response.getType() != MsgType.STOP
							&& response.getType() != MsgType.BAD_DETAILS);

				} catch (UnknownHostException unknownHost) {
					System.err
					.println("You are trying to connect to an unknown host!");
				} catch (IOException ioException) {
					ioException.printStackTrace();
				}
			}
		}
	}





	/**
	 * return which action, for sending to the server
	 * @return the which action message
	 */
	private Msg getRequest(){
		return new WhichActionMsg();
	}
	/**
	 * creating a file in the client's folder
	 * @param fileInByte - the file recieved from the server
	 * @param folderName - the folder's name
	 * @param fileName - the file's name
	 */
	private void createFile (byte[] fileInByte, String folderName, String fileName){
		File newFile = null;
		newFile = new File(clientDetails.mainFolder+"\\"+folderName+"\\"+fileName);
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(newFile);
			fos.write(fileInByte);
			fos.flush();
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}      

	}
	/**
	 * sending message to server
	 * @param msg - the message we want to send
	 */
	private void sendMessage(Msg msg)
	{
		try{
			out.writeObject(msg);
			out.flush();
			System.out.println("client>" + msg.getType());
		}
		catch(IOException ioException){
			ioException.printStackTrace();
		}
	}
	/**
	 * set stop receiving when user is stopping the service
	 * @param play
	 */
	public void setPlay(boolean play) {
		this.play = play;
	}
}
